package com.zkh.myutils.utils;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.Objects;
import java.util.function.Function;

/**
 * 字符串工具
 */
public class StringUtils {

 	/**
     * 判断指定字符串是否为空
     * @param str 指定的字符串
     * @return 若字符串为null或空串，则返回true；否则，返回false.
     */
    public static boolean isEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
    
    /**
     * 判断指定字符串是否不为空
     * @param str
     * @return
     */
    public static boolean isNotEmpty(String str) {
    	return !isEmpty(str);
    }
    
    /**
     * 检查字符串数组中是否存在元素为空值
     * @param strs
     * @return
     */
    public static boolean isExistEmpty(String... strs){
    	//遍历数组
    	for(String str: strs){
    		if(isEmpty(str)){
    			return true;
    		}
    	}
    	//执行到此处，说明数组元素均没有空值
    	return false;
    }
    
    /**
     * 判断指定字符串是否为某些值中的其中一个
     * @param target 指定字符串
     * @param checks 候选值
     * @return
     */
    public static boolean isExist(String target, String... checks){
    	return isExist(target, false, checks);
    }
    
    /**
     * 判断指定字符串是否为某些值中的其中一个
     * @param target 指定字符串
     * @param ignoreCase 是否忽略大小写
     * @param checks 候选值
     * @return
     */
    public static boolean isExist(String target, boolean ignoreCase, String... checks){
    	if(target==null || checks.length==0){
    		return false;
    	}
    	for(String check: checks){
    		if(ignoreCase ? (target.equalsIgnoreCase(check)) : (target.equals(check))){
    			return true;
    		}
    	}
    	return false;
    }
    
    /**
     * 检查指定字符串是否是邮箱
     * @param str 指定字符串
     * @return
     */
    public static boolean isEmail(String str){
    	return Regexp.isMatch("^[a-z0-9]+([._\\\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$", str);
    }
    
	/**
	 * 判断是否全部是数字(完全由数字组成)
	 * @param str
	 * @return
	 */
	public static boolean isNumber(String str){
		return Regexp.isMatch("^\\d+$", str);
	}
	
	/**
	 * 将字符串转换为数字
	 * @param str 待转换字符串。非数字格式，返回null
	 * @return
	 */
	public static BigDecimal getNumberic(String str) {
		return isNumeric(str) ? new BigDecimal(str) : null;
	}
	
	/**
	 * 将字符串转换为数字
	 * @param str 待转换字符串。非数字格式，返回默认值
	 * @return
	 */
	public static BigDecimal getNumberic(String str, double defaultValue) {
		return isNumeric(str) ? new BigDecimal(str) : BigDecimal.valueOf(defaultValue);
	}
	
	/**
	 * 判断是否是手机号码
	 * @param str
	 * @return
	 */
	public static boolean isPhoneNumber(String str){
		return Regexp.isMatch("^1\\d{10}$", str);
	}
	
	/**
	 * 判断字符串是否是数字<br />
	 * <b>数学意义上的数字，包含整数、小数、科学计数法标准格式，使用Float.parseFloat()能够正常转换。</b><br />
	 * 如：-5  0.1  2e3 都是数字
	 * @param str
	 * @return
	 */
	public static boolean isNumeric(String str){
		return isFloat(str);
	}
	
	/**
	 * 同时匹配开头和结尾
	 * @param str 要检查的字符串
	 * @param start 开头字符串
	 * @param end 结尾字符串
	 * @return
	 */
	public static boolean isOuterMatched(String str, String start, String end) {
		if(StringUtils.isEmpty(str)) {
			return false;
		}
		return str.startsWith(start) && str.endsWith(end);
	}
	
	/**
	 * 是否是整数
	 * @param str
	 * @return
	 */
	public static boolean isInteger(String str){
		return Regexp.isMatch("^\\-?\\d+$", str);
	}
	
	/**
	 * 是否是小数，整数也是小数，科学计数法统一默认为小数
	 * @param str
	 * @return
	 */
	public static boolean isFloat(String str){
		//标记
		boolean flag = false;
		//如果是普通小数或整数，都认为是小数
		if(Regexp.isMatch("^\\-?\\d+(\\.\\d+)?$", str)){
			flag = true;
		}
		//只要符合科学计数法的格式，都认为是小数
		else if(Regexp.isMatch("^\\-?\\d+(\\.\\d+)?([Ee]\\-?\\d+)$", str)){
			flag = true;
		}
		return flag;
	}
	
	/**
	 * 是否是正数
	 * @param str
	 * @return
	 */
	public static boolean isPositive(String str){
		//标记
		boolean flag = false;
		//如果是普通小数或整数，都认为是小数
		if(Regexp.isMatch("^\\+?\\d+(\\.\\d+)?$", str)){
			flag = true;
		}
		//只要符合科学计数法的格式，都认为是小数
		else if(Regexp.isMatch("^\\+?\\d+(\\.\\d+)?([Ee]\\-?\\d+)$", str)){
			flag = true;
		}
		return flag;
	}
	
	/**
	 * 是否是负数
	 * @param str
	 * @return
	 */
	public static boolean isNegative(String str){
		//标记
		boolean flag = false;
		//如果是普通小数或整数，都认为是小数
		if(Regexp.isMatch("^\\-\\d+(\\.\\d+)?$", str)){
			flag = true;
		}//只要符合科学计数法的格式，都认为是小数
		else if(Regexp.isMatch("^\\-\\d+(\\.\\d+)?([Ee]\\-?\\d+)$", str)){
			flag = true;
		}
		return flag;
	}
	
	/**
	 * 模拟Oracle的decode函数
	 * @param trans 字符串转对应类型
	 * @param varname 变量名
	 * @param decode 条件和取值，格式为。值1, 值为1时取值, 值2, 值为2时取值..., 值n, 值为n时取值[, 不为值1-值n时的取值]
	 * @return
	 */
	public static <T> T decode(Function<String, T> trans, String varname, String... decode) {
		return trans.apply(decode(varname, decode));
	}
	
	/**
	 * 模拟Oracle的decode函数
	 * @param varname 变量名
	 * @param decode 条件和取值，格式为。值1, 值为1时取值, 值2, 值为2时取值..., 值n, 值为n时取值[, 不为值1-值n时的取值]
	 * @return
	 */
	public static String decode(String varname, String... decode) {
		//没有参数
		if(decode==null || decode.length<=1) {
			return null;
		}
		//长度
		int len = decode.length;
		//遍历
		for(int i=0; i<len; i=i+2) {
			if(i!=len-1) {
				//变量值等于当前值
				if(Objects.equals(varname, decode[i])) {
					return decode[i+1];
				}
			}else {
				return len%2==0 ? null : decode[len-1];
			}
		}
		//其它均返回null
		return null;
	}
    
    /**
     * 将字符串首字母转大写
     * @param str
     */
    public static String uppercaseFirst(String str){
    	//字符串为null
    	if(str==null){
    		return null;
    	}
    	//字符串长度为0,1
    	if(str.length()<2){
    		return str.toUpperCase();
    	}else{
    		//字符串长度大于1
    		return str.substring(0, 1).toUpperCase()+str.substring(1);
    	}
    }
    
    /**
     * 将字符串首字母转小写
     * @param str
     * @return
     */
    public static String lowercaseFirst(String str){
    	//字符串为null
    	if(str==null){
    		return null;
    	}
    	//字符串长度为0,1
    	if(str.length()<2){
    		return str.toLowerCase();
    	}else{
    		//字符串长度大于1
    		return str.substring(0, 1).toLowerCase()+str.substring(1);
    	}
    }
    
    /**
     * 大小写互转
     * @param str
     * @return
     */
    public static String caseChange(String str) {
    	//为null
    	if(str==null) {
    		return null;
    	}
    	//新串
    	StringBuffer sb = new StringBuffer();
    	//转字符数组
    	char[] cs = str.toCharArray();
    	//遍历
    	for(char c: cs) {
    		if(Character.isUpperCase(c)) {
    			sb.append(Character.toLowerCase(c));
    		}else if(Character.isLowerCase(c)) {
    			sb.append(Character.toUpperCase(c));
    		}else {
    			sb.append(c);
    		}
    	}
    	//返回
    	return sb.toString();
    }
	
	/**
	 * 将一系列参数赋值到一段文本的占位符中
	 * @param message 一段文本，占位符使用 {index}，index为索引，从0开始。<br />&nbsp;&nbsp;
	 * <b>注：<br />&nbsp;&nbsp;&nbsp;&nbsp;
	 * 1、如果文本中需要将 { 和 } 当做普通字符，需用单引号引起来。<br />&nbsp;&nbsp;&nbsp;&nbsp;
	 * 2、如果需要将单引号当做普通字符，则需连续输入两个单引号。</b>
	 * @param params 一系列参数，按索引依次赋值给文本的占位符
	 * @return 格式后的文本
	 */
	public static String replaceByIndex(String message, Object... params){
		return MessageFormat.format(message, params);
	}
	
	/**
	 * 将文本中的占位符?用参数依次替换。不替换的占位符使用\?<br />
	 * <b>占位符过多的，未匹配到的占位符保持原样；参数过多的，直接忽略。</b>
	 * 
	 * @param message 需要替换的文本
	 * @param params 参数
	 * @return
	 */
	public static String replace(String message, Object... params){
		if(message==null){
			return null;
		}
		if(params==null){
			params = new Object[]{null};
		}
		for(Object p: params){
			message = message.replaceFirst("(?<=[^\\\\])\\?|^\\?", p==null?"null":p.toString());
		}
		//返回
		return message.replace("\\?", "?");
	}
	
	/**
	 * 多组替换规则依次进行替换，等同于多次调用String.replace
	 * @param string 待替换的字符
	 * @param replaces 替换规则，依次为[待替换字符串1, 替换后字符1, 待替换字符串2, 替换后字符2...]
	 * @return
	 */
	public static String replaces(String string, String... replaces) {
		//遍历
		for(int i=1, len=replaces.length; i<len; i+=2) {
			string = string.replace(replaces[i-1], replaces[i]);
		}
		//返回
		return string;
	}
	
	/**
	 * 多组替换规则依次进行替换，等同于多次调用String.replaceAll
	 * @param string 待替换的字符
	 * @param replaces 替换规则，依次为[正则替换规则1, 替换后字符1, 正则替换规则2, 替换后字符2...]
	 * @return
	 */
	public static String replacesAll(String string, String... replaces) {
		//遍历
		for(int i=1, len=replaces.length; i<len; i+=2) {
			string = string.replaceAll(replaces[i-1], replaces[i]);
		}
		//返回
		return string;
	}
	
	/**
	 * 去掉两端的指定字符
	 * @param value 待处理字符串
	 * @param c 指定字符
	 * @return
	 */
	public static String trim(String value, char c) {
		if(value==null) return null;
		char[] val = value.toCharArray();
		int len = val.length;
		int st = 0;
		while (st < len && val[st] == c) {
		    st++;
		}
		while (st < len && val[len - 1] == c) {
		    len--;
		}
		return ((st > 0) || (len < val.length)) ? value.substring(st, len) : value;
	}
	
	/**
	 * 转换为驼峰命名
	 * @param value 待转换字段
	 * @return
	 */
	public static String toCamelCase(String value) {
		if(value==null) return null;
		char[] val = trim(value, '_').toCharArray();
		int len = val.length;
		if(len==0) {
			return "";
		}
		StringBuffer sb = new StringBuffer();
		//遍历
		for(int i=0; i<len-1; i++) {
			sb.append(val[i]=='_' ? Character.toUpperCase(val[++i]) : val[i]);
		}
		return sb.append(val[len-1]).toString();
	}
}
